package CA;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;

import Share.Certificate;
import Share.TransmitStatus;

public class CA {
	//X.509
	/*
	private static final byte[] caKey = new byte[] {
	  48,-126,   1,  34,  48,  13,   6,   9,  42,-122,  72,-122,  -9,  13,   1,   1,
	   1,   5,   0,   3,-126,   1,  15,   0,  48,-126,   1,  10,   2,-126,   1,   1,
	   0, -70,  29, -20,  -1,  98, -47,-111, -49,  98, 115, -51,  10,  73,  45, -54,
	 104,  70, -85,  -1,-105,  98,   5,  93, -90,  17,  71,  82,  -2,  33, -50, 120,
	 118, -20,  84,  48,  49, -38,  18, -25, 124,  55, -54, 126, 115,  -6,  29,  41,
	 107,  79, -88,  66,  -3, -61, 110, -89,  82,  78,  32, 118,  40,  57, -23,  11,
	-104,-118,-124, -74,  47,-110, -12, -77,  67, -99,  83, -87,  48, -41, 124, -73,
	  97, -62,  99, -42,  19,-128,  72,   8, -15, -96,  46,-120, 118, -60,  74,  27,
	  11, -73,  64, 105, -67, -14,  29,  74,  89, -66, -15,-120,  62, -21,   0,-112,
	 -35, -27,-126, -48,  32,  67, -14, -75,-117,  97,  54,  94,  20, 122, -76, 103,
	  76,  76,-112,-103,  -7,-110,-101, -64, 101,   8,-102,-105, -61, -60,  23, -97,
	 -83,  38, -81,  83, -67,-117,-118, 127, 105,  22, -59,  25,   8,  80,-113,-110,
	  93,  35, -42,  20,-106, -84,  15, -84,   5, -24, -34,  29, -23, -62,  98, -51,
	 -96,  12, -70,  98, -92,  58,  14,-110,  22,  14, 105, -85,-113, -19, -68, -48,
	 112, -68, 115,-101, 120, -19, -40,  14, -27,  15,-126,-119, -54,-121, -82, -71,
	  46,  12,-100,  95,  39, -63,  32,  73, 103, 120, -44, 119,   0, -43,-128, 117,
	  82, 116,  61, -66,-119, -98, -44,-112, -83, -57, -55, -68,  54,-128, -55,  12,
	 122,-119, -67,-101, -21,  77, -10,  36, -68,  96, -75,  32, 111, -20,  12,-100,
	 -99,   2,   3,   1,   0,   1
	};*/
	//PKCS#8
	private static final byte[] privateKey = new byte[] {
	  48,-126,   4, -66,   2,   1,   0,  48,  13,   6,   9,  42,-122,  72,-122,  -9,
	  13,   1,   1,   1,   5,   0,   4,-126,   4, -88,  48,-126,   4, -92,   2,   1,
	   0,   2,-126,   1,   1,   0, -70,  29, -20,  -1,  98, -47,-111, -49,  98, 115,
	 -51,  10,  73,  45, -54, 104,  70, -85,  -1,-105,  98,   5,  93, -90,  17,  71,
	  82,  -2,  33, -50, 120, 118, -20,  84,  48,  49, -38,  18, -25, 124,  55, -54,
	 126, 115,  -6,  29,  41, 107,  79, -88,  66,  -3, -61, 110, -89,  82,  78,  32,
	 118,  40,  57, -23,  11,-104,-118,-124, -74,  47,-110, -12, -77,  67, -99,  83,
	 -87,  48, -41, 124, -73,  97, -62,  99, -42,  19,-128,  72,   8, -15, -96,  46,
	-120, 118, -60,  74,  27,  11, -73,  64, 105, -67, -14,  29,  74,  89, -66, -15,
	-120,  62, -21,   0,-112, -35, -27,-126, -48,  32,  67, -14, -75,-117,  97,  54,
	  94,  20, 122, -76, 103,  76,  76,-112,-103,  -7,-110,-101, -64, 101,   8,-102,
	-105, -61, -60,  23, -97, -83,  38, -81,  83, -67,-117,-118, 127, 105,  22, -59,
	  25,   8,  80,-113,-110,  93,  35, -42,  20,-106, -84,  15, -84,   5, -24, -34,
	  29, -23, -62,  98, -51, -96,  12, -70,  98, -92,  58,  14,-110,  22,  14, 105,
	 -85,-113, -19, -68, -48, 112, -68, 115,-101, 120, -19, -40,  14, -27,  15,-126,
	-119, -54,-121, -82, -71,  46,  12,-100,  95,  39, -63,  32,  73, 103, 120, -44,
	 119,   0, -43,-128, 117,  82, 116,  61, -66,-119, -98, -44,-112, -83, -57, -55,
	 -68,  54,-128, -55,  12, 122,-119, -67,-101, -21,  77, -10,  36, -68,  96, -75,
	  32, 111, -20,  12,-100, -99,   2,   3,   1,   0,   1,   2,-126,   1,   0,  76,
	 119, 107,  29, -22,  77, -52,  40, 118, 124, -71, 107,  86, 113,-105, -51,-117,
	 -21, -78, -47,  81,-106, 126, -55, 114,  35, -23, -73,  59, -48,-122, -79, -27,
	-101,  25,  74,   2,  28, -18,  58,-100,  -7, 119,  70, -45,  38,  20,  20,  96,
	 -33, -14, -42,  43, -21,  84,-105, 126,  61, -36,  13, -34, -19,  30, -76,-121,
	-124, -53,  13, 116, -59,  80, -71, -96, -13, -12, 121, 122, -81, 100, -16, -89,
	  91,  57,  99,  61, -69,  90, -31,  91,  60,-125,  24, -72, -64, -15, -89, -72,
	-100, -96,  85,  72,  26,  60, -89, -18, -55, 113, 126, -40,  50, -99,  82, 109,
	 -81, 119,  47,  42, 123,-105,-105,  50,  83,-110,   7, -69,  -6,  78, -51, -40,
	 117, 102, 126, 107, -96,  72, 100,  44, -17,  71, 121, -86, 126,  -6,-122, -89,
	  16,  89, -39, -58, 111,  34,  80, -33,  83, 113,  80, 111,-101,-100,  33,  60,
	 -98,-126, 110,  57,  41, 112, 116, 126,-117,  21,  42,  45, -18,   1, 104,  66,
	 -82,  13,  59,  93, -88,  80, -22, -39,-115, -22,-111, 114,-108,  36, -25, 125,
	  21, -12, -14, -95,  59,  68, -18, -73,  61,  16,  -5,-100, -95, -33, -45, -20,
	  79,  54,  34,  35,  -3, -69, -10,  27,   8,-126,  48, -84,   9, -65,  92,  49,
	 105,-115,  13,  41,-104,  64,  93,  16, 119,  20, -55,  82,  64, -96,  57,  31,
	 -95, 119,  98,  12,  83, 100,  43, 115,  91, -94, -15,   8,  34,  28,  65,   2,
	-127,-127,   0, -22,  -8,  39,  95,  14,  55,  21,  29,-117,-109,  15,-110, -54,
	   2,  53,   3,   9,-123,  92,  96,  13, -35, -64, 108,  79,  33, -35, 123,  30,
	  30,  82,  62,-100,-101,  69,-100,   9, -12,  65,  50,-116, -85, 118, -84,  96,
	  34,  77, -70,  79, -45,  29, -92,  67, -31, -17,  55, 127,  86, -12,  38,  89,
	 -16,  56,-125,-106, 107, -59,  -4,  39, 106, -11,  77,  72,   5,  25,-101, 102,
	  80, -19,-110, -49,  16, 119,  34,  89,  65, 115,  82,  82, -57,-113, -40,  49,
	 -96,  82,  39,  14,  17,-120,  97,   9,  81,-102, -20,-105, -48,-108, -81,  44,
	 -97,  -3,-117, 102,  52,  52, -82, -82,  -9, 110, -31,  -1, -24, -93,  48, 114,
	  -8,  -7, -71,   2,-127,-127,   0, -54, -58, 106, -59, 101,  32,  50,  18, -94,
	   4, -40, -45,  69,  86, -42, 123, -57,  47, -19, -91, -75,  29,  54,-115, -34,
	  72,  22,  87,  23,  34, -28,  78, 112, 105,  -2, 115, -27, 113,  84, -65, -17,
	 -82, -50,  53, 108, -46,-108, 105,-126, -10,  35, -31,-111,  43,  86, 116, -88,
	 -49, -17,  48,-113,  41, -44,  77, 127,-128, 119,  28,  40, 100,-113,-122,  72,
	 -92, 121,  92, -89, -11, -62, 108,-114, -99, -77,  66, -85, -48,   1,  68, 114,
	 -35,-112,  19, -43, -31,-106,-105, 116,  87,  99, -16, -89,-113,  -4,  87,  33,
	 -26,-107, 115, 114, -73, -42,-119, -84,  -3, -70,  86,  89, -21,  35, -98, 124,
	  48, 109,  -3, -46,-101,-100,   5,   2,-127,-127,   0, -48,  51,-104,  -9,  98,
	 106,  46, 124, -94,-117, 105, -74,  64, -25,  89, -65, -38,  52, -32,  88,-128,
	-112, -24,-117,  80,  71,  10, -80, -88,  76, 103, -59, -15,  16, -88, -54,-114,
	  11, 111, -91, -15,  -3,-112, -57,  70, -37, -66,-110,   3,  95, 103,  25,-127,
	 -56, -10,  37, -17, -32, -59, -80,  33, -21, 120, -72,  40,-106,  80, -75,-112,
	 -37, -10,-122,  70, -11, -75, -19,  -5, -24,  99, -54, -67,  77, -78, -78, -83,
	 -14,  15, -44, 119,  99,  59,  51, 111,  45, -58,  -3, -78,  58,-104, -28,-102,
	 -44,  67, 121, -73,  63, -20,  47,-104,  84,  31, -34, -32, 110,  11, -20, 105,
	  62,  -8, 114, -85,  70, -95,  43,  50,   5,  41,-119,   2,-127,-127,   0, -80,
	-116, -61,-121, -20, -67, 116, 123, 126, -81, -93, -83,-121, 112, -51,  60, 102,
	  56,  87, -68, -16,-115, 103, -29, 107, -58, -18,  20,-109, -29,  96,  78, -33,
	  87,-102,  33,-124,-125,   1,  92,  64,  46, -66,   2,  12,  38, -24, -21,  89,
	   8,  64,  67, 116, 102,  -4,  86,-124, 104, -49,   4,  67,-110,  18, -12,  10,
	 -16, 106,  68,-116, -14, -55, 120,  12, -91,-113, -71,  89, -48,   3, -95,  11,
	  39,  73,  93, -30,  68,  47, -26,  77, -16,-107,  50,-128,   5, 115,  93,-103,
	   1,  65, -43, -43, -66, -22, -31,  94, 117, -22, 103, -29,  89,  39,  37,  38,
	   6, -96,-121, -16, -80, 103,-119, -28, -19,  49, -57,  78, -23,   7,-107,   2,
	-127,-128,  16,-123,  15,-101,  27,  72, -16, 116,  89, -31, -38, 105, -28, -34,
	  98,  -3,  65,-117, 103, -35,-105,  28, 106,  41,  83, -50, -85, -23,  61,-102,
	 -14, -26, -17,  38,  69, -93, 100,  -9, -73, 105,  73,  58, -64,-120, 125,  14,
	 116,-117,-116, -76, -93,  48, 119, -68, 110,  40,-120,  24,  39, -85,  29, -33,
	 -82, 105, 114,  14,-119,  -7, -46,  42,  45,  55, -32,  38, -95,  18, -47, 126,
	 122,  60, -40,  99, -80,  30, -40,  94,  64,  74,  25,  15, -73, -91,  12, -80,
	 118,-118,  -4, -49,-127,-102, -56, -43,  68, -94, -61, -82,  38,  -7, 127,  -3,
	  80,-105,  -8,  95, -62,  78,  21, 113,  59, 122, -10, -18,-115,  91,  23,  86,
	  84, -16
	};
	
	//The following is used to generate initial hard coded CA keys
	/*
	private static void generteNewKeys()
	{
		KeyPairGenerator keyGen;
		try {
			keyGen = KeyPairGenerator.getInstance("RSA");
			keyGen.initialize(2048);
			KeyPair key = keyGen.genKeyPair();
			
			byte[] k = key.getPublic().getEncoded();
			
			System.out.print("//");
			System.out.println(key.getPublic().getFormat());
			System.out.print("private static final byte[] caKey = new byte[] {");
			System.out.println();
			System.out.format("%1$4d", k[0]);
			for(int i = 1; i < k.length; i++)
			{
				System.out.print(",");
				if(i % 16 == 0)
					System.out.println();
				System.out.format("%1$4d", k[i]);

			}
			System.out.println();
			System.out.print("};");
			System.out.println();
			
			k = key.getPrivate().getEncoded();
			
			System.out.print("//");
			System.out.println(key.getPrivate().getFormat());
			System.out.print("private static final byte[] privateKey = new byte[] {");
			System.out.println();
			System.out.format("%1$4d",k[0]);
			for(int i = 1; i < k.length; i++)
			{
				System.out.print(",");
				if(i % 16 == 0)
					System.out.println();
				System.out.format("%1$4d", k[i]);
			}
			System.out.println();
			System.out.print("};");
		} catch (NoSuchAlgorithmException e) {

		}
	}
	*/
	
	private static Certificate generateCert(String name, byte[] key, Cipher cipher) throws IllegalBlockSizeException, BadPaddingException
	{
		Date expiration = new Date();
		expiration.setTime(expiration.getTime() + 31556926000L);
		
		Certificate cert = new Certificate(name, "the_big_ca",  expiration, key);
		cert.signature = cipher.doFinal(cert.hashForSig());
		
		return cert;
	}
	
	public static final int DEFAULT_CA_PORT = 5050;
	
	public static void main(String[] args)
	{
		
		/*generteNewKeys();
		if(1 > 0)
			return;*/
		
		
		int port = DEFAULT_CA_PORT;
		
		if(args.length > 0)
		{
			try
			{
				port = Integer.parseInt(args[0]);
			}
			catch(Exception e)
			{
				port = -1;
			}
			
		}
		if(port < 0 || port > 65535)
		{
			System.out.println("Bad port number!");
			return;
		}
		
		try
		{
			PrivateKey key = null;
			try
			{
				key = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKey));
			}
			catch(Exception e)
			{
				e.printStackTrace();
				return;
			}
			Cipher cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, key);
			System.out.format("Lisenting on prot: %1$d", port);
			System.out.println();
			ServerSocket server = new ServerSocket(port);
			while(true)
			{
				Socket socket = server.accept();
				DataInputStream in = new DataInputStream(socket.getInputStream());
				DataOutputStream out = new DataOutputStream(socket.getOutputStream());
				
				try
				{
					int data = in.readInt();
					byte[] buff = new byte[data];
					in.read(buff);
					String name = new String(buff, "UTF-8");
					
					data = in.readInt();
					buff = new byte[data];
					in.read(buff);
					byte[] pubKey = buff;
					
					
					if(!name.matches("^\\w*$"))
					{
						out.write(TransmitStatus.invalidName.ordinal());
						continue;
					}
					
					Certificate cert;
					try
					{
						cert = generateCert(name, pubKey, cipher);
					}
					catch(Error e)
					{
						out.write(TransmitStatus.error.ordinal());
						continue;
					}
					
					BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
					
					while(true)
					{
						System.out.println();
						System.out.format("Grant ticket to '%1$s:%2$d' under the name '%3$s' (y|n):", socket.getInetAddress().getHostAddress(), socket.getPort(), cert.owner);
						String c = reader.readLine().toLowerCase() ;
						if(c.equals("y") || c.equals("yes"))
						{
							System.out.println("yes");
							out.write(TransmitStatus.success.ordinal());
							cert.serialize(out);
							out.flush();
							break;
						}
						else if(c.equals("n") || c.equals("no"))
						{
							System.out.println("no");
							out.write(TransmitStatus.certificateDenied.ordinal());
							out.flush();
							break;
						}
					}
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
				finally
				{
					try
					{
						out.close();
						in.close();
						socket.close();
					}
					catch(Exception e)
					{
						e.printStackTrace();
					}
				}
				
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		

	}
}
